module dungeon.monster_group;

import std.conv;

import derelict.opengl.gl;

import nade.random;
import nade.ast;
import nade.loader;
import nade.vector;

import dungeon.game;
import dungeon.map;
import dungeon.monster;


class MonsterChance {
	string		name;
	int			depthMin = 1, depthMax = int.max, chance = 100;
}

class MonsterGroup {
	this(Game game)
	{
		_game = game;
	}

	MonsterObject spawn(Map map, const Vector2i coord)
	{
		auto monster = this.getRandomMonster(map.depth);
		return new MonsterObject(map, coord, map.game.getMonster(monster.name));
	}

	MonsterChance getRandomMonster(int depth)
	{
		MonsterChance[] possibles;
		int chanceTotal = 0;

		foreach(monster; _monsters)
		{
			if(depth >= monster.depthMin  &&  depth <= monster.depthMax)
			{
				possibles ~= monster;
				chanceTotal += monster.chance;
			}
		}

		if(chanceTotal == 0) assert(false);

		int r = random(0, chanceTotal);
		foreach(monster; possibles)
		{
			r -= monster.chance;
			if(r < 0) return monster;
		}

		assert(false);
	}

	string id() { return _id; }
	string name() { return _name; }
	MonsterGroup base() { return _base; }

	protected {
		Game				_game;
		string				_id, _name;
		MonsterGroup		_base = null;

		MonsterChance[]		_monsters;
	}

	static void install()
	{
		static MonsterGroup current = null;

		Loader!(MonsterGroup).add("name",
			(ref MonsterGroup group, AST ast, Object[string] state)
			{
				group._id = ast[0].as!string;
				group._name = ast[1].as!string;
				group._game.addMonsterGroup(group);
			}
		);
		Loader!(MonsterGroup).add("base",
			(ref MonsterGroup group, AST ast, Object[string] state)
			{
				group._base = group._game.getMonsterGroup(ast[0].as!string);
			}
		);
		Loader!(MonsterGroup).add("monster",
			(ref MonsterGroup group, AST ast, Object[string] state)
			{
				auto prev = current;
				current = group;

				auto monster = new MonsterChance;
				load(monster, ast, state);
				group._monsters ~= monster;

				current = prev;
			}
		);

		Loader!(MonsterChance).add(0,
			(ref MonsterChance monster, AST ast, Object[string] state)
			{
				monster.name = ast.as!string;
			}
		);
		Loader!(MonsterChance).add("depth",
			(ref MonsterChance monster, AST ast, Object[string] state)
			{
				monster.depthMin = monster.depthMax = ast[0].as!int;
				if(ast.length >= 2) monster.depthMax = ast[1].as!int;
			}
		);
		Loader!(MonsterChance).add("chance",
			(ref MonsterChance monster, AST ast, Object[string] state)
			{
				monster.chance = ast[0].as!int;
			}
		);
	}
}
